/*
 * Filename: g:\espidf_workspace\idf_S3_T-Watch\main\audio\adf_service.cc
 * Path: g:\espidf_workspace\idf_S3_T-Watch\main\audio
 * Created Date: Monday, June 30th 2025, 1:54:04 pm
 * Author: sss
 *
 * Copyright (c) 2025 Your Company
 */

#include "adf_service.h"
#include "esp_log.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/ringbuf.h"
#include "driver/i2s.h"
#include "driver/i2s_types.h"
#include "driver/i2s_std.h"
#include "utils.h"

#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "audio_common.h"
#include "fatfs_stream.h"
#include "http_stream.h"
#include "i2s_stream.h"
#include "mp3_decoder.h"
#include "pcm_decoder.h"
#include "tts_stream.h"
#include "esp_peripherals.h"

#include "raw_stream.h"
#include "filter_resample.h"
#include "esp_vad.h"

#include <string.h>
#include <ctype.h>

#define OPUS_SAMPLE_RATE 48000 // 48kHz采样率
#define MP3_SAMPLE_RATE 44100  // 44.1kHz采样率
// #define MP3_SAMPLE_RATE_128 128000 // 128kHz采样率
#define PCM_SAMPLE_RATE 16000 // 16kHz采样率
#define TTS_SAMPLE_RATE 16000 // 16kHz采样率
#define I2S_CHANNELS 1        // 单声道
#define PCM_CHANNELS 1        // 单声道
#define ADF_SERVICE_CORE 1    // 核心1

#define VAD_SAMPLE_RATE_HZ 16000
#define VAD_FRAME_LENGTH_MS 30
#define VAD_BUFFER_LENGTH (VAD_FRAME_LENGTH_MS * VAD_SAMPLE_RATE_HZ / 1000)

static const char *TAG = "ADF_SERVICE";

static audio_pipeline_handle_t pipeline;
static audio_element_handle_t fatfs_stream_reader, http_stream_reader, tts_stream_reader, i2s_stream_reader, filter, raw_read, i2s_stream_writer, mp3_decoder, pcm_decoder, opus_decoder;
static esp_periph_set_handle_t set;
static audio_event_iface_handle_t evt;

static void event_handler_task(void *arg)
{
    audio_event_iface_handle_t event_iface = (audio_event_iface_handle_t)arg;
    audio_event_iface_msg_t msg;

    while (1)
    {
        // 非阻塞读取事件（超时设为 0）
        if (audio_event_iface_listen(event_iface, &msg, portMAX_DELAY) == ESP_OK)
        {
            // 快速处理事件（如更新状态标志）
            if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT &&
                msg.cmd == AEL_MSG_CMD_REPORT_STATUS)
            {
                ESP_LOGI(TAG, "Audio event reported from element");
            }

            if (msg.source_type == AUDIO_ELEMENT_TYPE_ELEMENT && msg.source == (void *)mp3_decoder && msg.cmd == AEL_MSG_CMD_REPORT_MUSIC_INFO)
            {
                audio_element_info_t music_info = {0};
                audio_element_getinfo(mp3_decoder, &music_info);

                ESP_LOGI(TAG, "[ * ] Receive music info from mp3 decoder, sample_rates=%d, bits=%d, ch=%d",
                         music_info.sample_rates, music_info.bits, music_info.channels);

                i2s_stream_set_clk(i2s_stream_writer, music_info.sample_rates, music_info.bits, music_info.channels);
                continue;
            }
        }
        vTaskDelay(10 / portTICK_PERIOD_MS); // 适当让出 CPU
    }

    vTaskDelete(NULL);
}

static void adf_service_vad_task(void *arg)
{
    ADF_SERVICE& adf_service = ADF_SERVICE::get_instance();
    adf_service.run_vad();
    vTaskDelete(NULL);

}


void ADF_SERVICE::init()
{
    if (initialized)
    {
        ESP_LOGI(TAG, "ADF_SERVICE has been initialized");
        return;
    }

    initialized = true;

    ESP_LOGI(TAG, "[ 1 ] Start audio codec chip");
    esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
    periph_cfg.task_core = ADF_SERVICE_CORE; // 在第二个核心上运行
    set = esp_periph_set_init(&periph_cfg);

    ESP_LOGI(TAG, "[ 2 ] Start pipeline");
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    pipeline = audio_pipeline_init(&pipeline_cfg);
    mem_assert(pipeline);

    ESP_LOGI(TAG, "[3.1] Start file stream reader");
    fatfs_stream_cfg_t fatfs_cfg = FATFS_STREAM_CFG_DEFAULT();
    fatfs_cfg.type = AUDIO_STREAM_READER;
    fatfs_cfg.task_core = ADF_SERVICE_CORE; // 在第二个核心上运行
    fatfs_stream_reader = fatfs_stream_init(&fatfs_cfg);
    audio_pipeline_register(pipeline, fatfs_stream_reader, "file");

    ESP_LOGI(TAG, "[3.2] Create http stream to read data");
    http_stream_cfg_t http_cfg = HTTP_STREAM_CFG_DEFAULT();
    http_cfg.type = AUDIO_STREAM_READER;
    http_cfg.task_core = ADF_SERVICE_CORE; // 在第二个核心上运行
    http_stream_reader = http_stream_init(&http_cfg);
    audio_pipeline_register(pipeline, http_stream_reader, "http");

    ESP_LOGI(TAG, "[3.3] Create tts stream to read text");
    tts_stream_cfg_t tts_cfg = TTS_STREAM_CFG_DEFAULT();
    tts_cfg.type = AUDIO_STREAM_READER;
    tts_cfg.task_core = ADF_SERVICE_CORE; // 在第二个核心上运行
    tts_stream_reader = tts_stream_init(&tts_cfg);
    tts_stream_set_speed(tts_stream_reader, TTS_VOICE_SPEED_1); // 设置语速 0-5
    audio_pipeline_register(pipeline, tts_stream_reader, "tts");

    ESP_LOGI(TAG, "[3.4] Create i2s stream to read data");
    i2s_stream_cfg_t i2s_reader_cfg = I2S_STREAM_CFG_DEFAULT_WITH_PARA(I2S_NUM_1, 48000, I2S_DATA_BIT_WIDTH_16BIT, AUDIO_STREAM_READER);
    i2s_reader_cfg.task_core = ADF_SERVICE_CORE; // 在第二个核心上运行
    i2s_stream_reader = i2s_stream_init(&i2s_reader_cfg);
    audio_pipeline_register(pipeline, i2s_stream_reader, "i2s_reader");

    ESP_LOGI(TAG, "[3.4] Create filter to resample audio data");
    rsp_filter_cfg_t rsp_cfg = DEFAULT_RESAMPLE_FILTER_CONFIG();
    rsp_cfg.src_rate = 48000;
    rsp_cfg.src_ch = 2;
    rsp_cfg.dest_rate = VAD_SAMPLE_RATE_HZ;
    rsp_cfg.dest_ch = 1;
    rsp_cfg.task_core = ADF_SERVICE_CORE; // 在第二个核心上运行
    filter = rsp_filter_init(&rsp_cfg);
    audio_pipeline_register(pipeline, filter, "filter");

    ESP_LOGI(TAG, "[3.5] Create raw to receive data");
    raw_stream_cfg_t raw_cfg = {
        .type = AUDIO_STREAM_READER,
        .out_rb_size = 8 * 1024,
    };
    raw_read = raw_stream_init(&raw_cfg);
    audio_pipeline_register(pipeline, raw_read, "raw_read");

    ESP_LOGI(TAG, "[4] Create i2s stream");
    i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg.type = AUDIO_STREAM_WRITER;
    i2s_cfg.task_core = ADF_SERVICE_CORE; // 在第二个核心上运行
    i2s_stream_writer = i2s_stream_init(&i2s_cfg);
    audio_pipeline_register(pipeline, i2s_stream_writer, "i2s");

    ESP_LOGI(TAG, "[5] Create mp3 decoder");
    mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG();
    mp3_cfg.task_core = ADF_SERVICE_CORE; // 在第二个核心上运行
    mp3_decoder = mp3_decoder_init(&mp3_cfg);
    audio_pipeline_register(pipeline, mp3_decoder, "mp3");

    ESP_LOGI(TAG, "[6] Create pcm decoder");
    pcm_decoder_cfg_t pcm_cfg = DEFAULT_PCM_DECODER_CONFIG();
    pcm_cfg.task_core = ADF_SERVICE_CORE; // 在第二个核心上运行
    pcm_cfg.rate = PCM_SAMPLE_RATE;
    pcm_cfg.channels = PCM_CHANNELS;
    pcm_decoder = pcm_decoder_init(&pcm_cfg);
    audio_pipeline_register(pipeline, pcm_decoder, "pcm");

    ESP_LOGI(TAG, "[7] Set up  event listener");
    audio_event_iface_cfg_t evt_cfg = AUDIO_EVENT_IFACE_DEFAULT_CFG();
    evt = audio_event_iface_init(&evt_cfg);

    ESP_LOGI(TAG, "[8] Listening event from all elements of pipeline");
    audio_pipeline_set_listener(pipeline, evt);

    ESP_LOGI(TAG, "[9] Listening event from peripherals");
    audio_event_iface_set_listener(esp_periph_set_get_event_iface(set), evt);
}
void ADF_SERVICE::deinit()
{
    if (!initialized)
    {
        ESP_LOGI(TAG, "ADF_SERVICE not initialized");
        return;
    }
    initialized = false;

    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);

    /* Terminate the pipeline before removing the listener */
    audio_pipeline_unregister(pipeline, fatfs_stream_reader);
    audio_pipeline_unregister(pipeline, http_stream_reader);
    audio_pipeline_unregister(pipeline, tts_stream_reader);
    audio_pipeline_unregister(pipeline, i2s_stream_writer);
    audio_pipeline_unregister(pipeline, mp3_decoder);
    audio_pipeline_unregister(pipeline, pcm_decoder);

    audio_pipeline_remove_listener(pipeline);

    esp_periph_set_stop_all(set);
    audio_event_iface_remove_listener(esp_periph_set_get_event_iface(set), evt);
    audio_event_iface_destroy(evt);

    /* Release all resources */
    audio_pipeline_deinit(pipeline);
    audio_element_deinit(fatfs_stream_reader);
    audio_element_deinit(http_stream_reader);
    audio_element_deinit(tts_stream_reader);
    audio_element_deinit(i2s_stream_writer);
    audio_element_deinit(mp3_decoder);
    audio_element_deinit(pcm_decoder);
    esp_periph_set_destroy(set);
}

void ADF_SERVICE::reset_pipeline()
{
    init();
    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    // audio_pipeline_terminate(pipeline);
    audio_pipeline_unlink(pipeline);
}

void ADF_SERVICE::play_tts(const char *text)
{
    reset_pipeline();
    i2s_stream_set_clk(i2s_stream_writer, TTS_SAMPLE_RATE, 16, 1);
    ESP_LOGI(TAG, "Start to play TTS");
    const char *link_tag[2] = {"tts", "i2s"};
    audio_pipeline_link(pipeline, &link_tag[0], 2);
    tts_stream_set_strings(tts_stream_reader, text);
    audio_pipeline_run(pipeline);
}

void ADF_SERVICE::play_file(const char *file_path)
{
    reset_pipeline();
    audio_element_set_uri(fatfs_stream_reader, file_path);
    char audio_url_lower[100];
    strcpy(audio_url_lower, file_path);
    to_lower(audio_url_lower);
    // 判断url是否为mp3
    if (strstr(audio_url_lower, ".mp3"))
    {
        const char *link_tag[3] = {"file", "mp3", "i2s"};
        audio_pipeline_link(pipeline, &link_tag[0], 3);
        audio_pipeline_run(pipeline);
    }
    else if (strstr(audio_url_lower, ".pcm"))
    {
        const char *link_tag[3] = {"file", "pcm", "i2s"};
        audio_pipeline_link(pipeline, &link_tag[0], 3);
        audio_pipeline_run(pipeline);
    }
    else
    {
        ESP_LOGE(TAG, "Unsupported audio type");
        return;
    }
}

void ADF_SERVICE::play_url(const char *url)
{
    ESP_LOGI(TAG, "Start to play URL %s", url);
    reset_pipeline();
    esp_err_t ret = audio_element_set_uri(http_stream_reader, url);
    if (ret != ESP_OK)
    {
        ESP_LOGE(TAG, "Set url failed %s", esp_err_to_name(ret));
    }
    char audio_url_lower[100];
    strcpy(audio_url_lower, url);
    to_lower(audio_url_lower);
    // 判断url是否为mp3
    if (strstr(audio_url_lower, ".mp3"))
    {
        ret = i2s_stream_set_clk(i2s_stream_writer, MP3_SAMPLE_RATE, 16, 2);
        if (ret != ESP_OK)
        {
            ESP_LOGE(TAG, "Set i2s clock failed %s", esp_err_to_name(ret));
        }
        const char *link_tag[3] = {"http", "mp3", "i2s"};
        audio_pipeline_link(pipeline, &link_tag[0], 3);
        audio_pipeline_run(pipeline);
    }
    else if (strstr(audio_url_lower, ".pcm"))
    {
        ret = i2s_stream_set_clk(i2s_stream_writer, PCM_SAMPLE_RATE, 16, 1);
        if (ret != ESP_OK)
        {
            ESP_LOGE(TAG, "Set i2s clock failed %s", esp_err_to_name(ret));
        }
        const char *link_tag[3] = {"http", "pcm", "i2s"};
        audio_pipeline_link(pipeline, &link_tag[0], 3);
        audio_pipeline_run(pipeline);
    }
    else
    {
        ESP_LOGE(TAG, "Unsupported audio type");
        return;
    }
}

void ADF_SERVICE::play_pcm_stream(uint8_t *data, int len)
{
    reset_pipeline();
}

void ADF_SERVICE::stop_play()
{
}

void ADF_SERVICE::pause_play()
{
    audio_pipeline_pause(pipeline);
}

void ADF_SERVICE::resume_play()
{
}

void ADF_SERVICE::set_volume(int volume)
{
}

void ADF_SERVICE::run_vad()
{
    ESP_LOGI(TAG, "Start to run VAD");
    reset_pipeline();

    const char *link_tag[3] = {"i2s_reader", "filter", "raw_read"};
    audio_pipeline_link(pipeline, &link_tag[0], 3);

    audio_pipeline_run(pipeline);

    ESP_LOGI(TAG, "Initialize VAD handle");
    vad_handle_t vad_inst = vad_create(VAD_MODE_0);

    int16_t *vad_buff = (int16_t *)malloc(VAD_BUFFER_LENGTH * sizeof(short));
    if (vad_buff == NULL) {
        ESP_LOGE(TAG, "Memory allocation failed!");
        goto abort_speech_detection;
    }

    while (1) {
        raw_stream_read(raw_read, (char *)vad_buff, VAD_BUFFER_LENGTH * sizeof(short));

        // Feed samples to the VAD process and get the result
        vad_state_t vad_state = vad_process(vad_inst, vad_buff, VAD_SAMPLE_RATE_HZ, VAD_FRAME_LENGTH_MS);
        if (vad_state == VAD_SPEECH) {
            ESP_LOGI(TAG, "Speech detected");
            break;
        }
    }
abort_speech_detection:
    free(vad_buff);
    vad_buff = NULL;


}
void ADF_SERVICE::stop_vad()
{
    reset_pipeline();
}

ADF_SERVICE::ADF_SERVICE()
{
    xTaskCreate(event_handler_task, "adf_service_event_task", 4096, evt, 10, NULL);
    xTaskCreatePinnedToCore(adf_service_vad_task, "adf_service_vad_task", 4096, this, 10, NULL, ADF_SERVICE_CORE);
}
ADF_SERVICE::~ADF_SERVICE()
{
}